home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue72 / alfresco / AAHuffmn.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2001-07-05  |  30.9 KB  |  1,010 lines

  1. {*********************************************************}
  2. {* AAHuffmn                                              *}
  3. {* Copyright (c) Julian M Bucknall 1999, 2000            *}
  4. {* All rights reserved.                                  *}
  5. {*********************************************************}
  6. {* Huffman compression and decompression                 *}
  7. {*********************************************************}
  8.  
  9. {Note: this unit is released as freeware. In other words, you are free
  10.        to use this unit in your own applications, however I retain all
  11.        copyright to the code. JMB}
  12.  
  13. unit AAHuffmn;
  14.  
  15. {Version 1: initial release}
  16. {Version 2: New method for writing/reading the Huffman tree}
  17.  
  18. interface
  19.  
  20. uses
  21.   SysUtils, Classes;
  22.  
  23. {$IFOPT D+}
  24. {$DEFINE InDebugMode}
  25. {$ENDIF}
  26.  
  27. procedure HuffmanCompress(aInStream, aOutStream : TStream);
  28. procedure HuffmanDecompress(aInStream, aOutStream : TStream);
  29.  
  30. procedure HuffmanCompressBlock(var aBuffer;
  31.                                    aSize      : integer;
  32.                                    aOutStream : TStream);
  33. procedure HuffmanDecompressBlock(aInStream : TStream;
  34.                              var aBuffer;
  35.                                  aSize     : integer);
  36.  
  37. implementation
  38.  
  39. const
  40.   vaByte    = 0;   {value is a byte: 0..255}
  41.   vaWord    = 1;   {value is a word: 255..65535}
  42.   vaLongint = 2;   {value is a longint: all other values}
  43.  
  44. const
  45.   Bit : array [0..7] of byte =  {bit masks}
  46.         ($01, $02, $04, $08, $10, $20, $40, $80);
  47.  
  48. type
  49.   PHuffmanNode = ^THuffmanNode;
  50.   THuffmanNode = packed record
  51.     hnCount    : longint;
  52.     hnLeftInx  : longint;
  53.     hnRightInx : longint;
  54.   end;
  55.  
  56.   PHuffmanTree = ^THuffmanTree;
  57.   THuffmanTree = array [0..510] of THuffmanNode;
  58.  
  59. type
  60.   THuffmanCodeStr = string[255];
  61.  
  62.   PHuffmanCode = ^THuffmanCode;
  63.   THuffmanCode = packed record
  64.     hcBitCount : longint;
  65.     hcCode     : array [0..31] of byte;
  66.   end;
  67.  
  68.   PHuffmanCodes = ^THuffmanCodes;
  69.   THuffmanCodes = array [0..255] of THuffmanCode;
  70.  
  71.  
  72. {===THuffmanPriorityQueue=============================================}
  73. type
  74.   longint = integer;
  75.  
  76.   THuffmanPriorityQueue = class
  77.     {-A priority queue for Huffman compression}
  78.     private
  79.       pqList : TList;
  80.       pqTree : PHuffmanTree;
  81.     protected
  82.       function pqGetCount : integer;
  83.  
  84.       procedure pqBubbleUp(aFromInx : integer; aItem : longint);
  85.       procedure pqTrickleDown(aFromInx : integer; aItem : longint);
  86.     public
  87.       constructor Create(aHTree : PHuffmanTree);
  88.         {-Create the priority queue}
  89.       destructor Destroy; override;
  90.         {-Dispose of the priority queue}
  91.  
  92.       procedure Add(aItem : longint);
  93.         {-Add an item (ie, Huffman tree index) to the priority queue}
  94.       function Remove : longint;
  95.         {-Remove and return the item (ie, Huffman tree index) with the
  96.           smallest count}
  97.  
  98.       property Count : integer read pqGetCount;
  99.         {-Count of items in the queue}
  100.  
  101.       property List : TList read pqList;
  102.   end;
  103. {--------}
  104. constructor THuffmanPriorityQueue.Create(aHTree : PHuffmanTree);
  105. begin
  106.   inherited Create;
  107.   {create the queue's array; we know it'll be at most 256 elements}
  108.   pqList := TList.Create;
  109.   pqList.Capacity := 256;
  110.   {remember the Huffman tree we're using}
  111.   pqTree := aHTree;
  112. end;
  113. {--------}
  114. destructor THuffmanPriorityQueue.Destroy;
  115. begin
  116.   pqList.Free;
  117.   inherited Destroy;
  118. end;
  119. {--------}
  120. procedure THuffmanPriorityQueue.Add(aItem : longint);
  121. begin
  122.   {add extra space at the end of the queue}
  123.   pqList.Count := pqList.Count + 1;
  124.   {now bubble the item up as far as it will go}
  125.   pqBubbleUp(pred(pqList.Count), aItem);
  126. end;
  127. {--------}
  128. procedure THuffmanPriorityQueue.pqBubbleUp(aFromInx : integer;
  129.                                            aItem    : longint);
  130. var
  131.   ParentInx : integer;
  132.   ItemCount : longint;
  133. begin
  134.   {while the item under consideration is smaller than its parent, swap
  135.    it with its parent and continue from its new position}
  136.   {Note: the parent for the child at index N is at (N-1) div 2}
  137.   ItemCount := pqTree^[aItem].hnCount;
  138.   ParentInx := (aFromInx - 1) div 2;
  139.   {while our item has a parent, and it's greater than the parent...}
  140.   while (aFromInx > 0) and
  141.         (ItemCount <
  142.            pqTree^[longint(pqList[ParentInx])].hnCount) do begin
  143.     {move our parent down the tree}
  144.     pqList[aFromInx] := pqList[ParentInx];
  145.     aFromInx := ParentInx;
  146.     ParentInx := (aFromInx - 1) div 2;
  147.   end;
  148.   {store our item in the correct place}
  149.   pqList[aFromInx] := pointer(aItem);
  150. end;
  151. {--------}
  152. function THuffmanPriorityQueue.pqGetCount : integer;
  153. begin
  154.   Result := pqList.Count;
  155. end;
  156. {--------}
  157. procedure THuffmanPriorityQueue.pqTrickleDown(aFromInx : integer;
  158.                                               aItem    : longint);
  159. var
  160.   ChildInx  : integer;
  161.   ListCount : integer;
  162.   ItemCount : longint;
  163. begin
  164.   {while the item under consideration is greater than one of its
  165.    children, swap it with the smaller child and continue from its new
  166.    position}
  167.   {Note: the children for the parent at index N are at (2N+1) and
  168.          2N+2}
  169.   ItemCount := pqTree^[aItem].hnCount;
  170.   ListCount := pqList.Count;
  171.   {calculate the left child index}
  172.   ChildInx := succ(aFromInx * 2);
  173.   {while there is at least a left child...}
  174.   while (ChildInx < ListCount) do begin
  175.     {if there is a right child, calculate the index of the smaller
  176.      child}
  177.     if (succ(ChildInx) < ListCount) and
  178.        (pqTree^[longint(pqList[ChildInx])].hnCount >
  179.           pqTree^[longint(pqList[succ(ChildInx)])].hnCount) then
  180.       inc(ChildInx);
  181.     {if our item is less or equal to the smaller child, we're done}
  182.     if (ItemCount <= pqTree^[longint(pqList[ChildInx])].hnCount) then
  183.       Break;
  184.     {otherwise move the smaller child up the tree, and move our item
  185.      down the tree and repeat}
  186.     pqList[aFromInx] := pqList[ChildInx];
  187.     aFromInx := ChildInx;
  188.     ChildInx := succ(aFromInx * 2);
  189.   end;
  190.   {store our item in the correct place}
  191.   pqList[aFromInx] := pointer(aItem);
  192. end;
  193. {--------}
  194. function THuffmanPriorityQueue.Remove : longint;
  195. begin
  196.   {return the item at the root}
  197.   Result := longint(pqList[0]);
  198.   {replace the root with the child at the lowest, rightmost position,
  199.    and shrink the list}
  200.   pqList[0] := pqList.Last;
  201.   pqList.Count := pqList.Count - 1;
  202.   {now trickle down the root item as far as it will go}
  203.   if (pqList.Count > 0) then
  204.     pqTrickleDown(0, longint(pqList[0]));
  205. end;
  206. {====================================================================}
  207.  
  208.  
  209. {===bit streams======================================================}
  210. const
  211.   StreamBufferSize = 4096;
  212. type
  213.   TInputBitStream = class
  214.     private
  215.       FAccum      : byte;
  216.       FBufEnd     : integer;
  217.       FBuffer     : PAnsiChar;
  218.       FBufPos     : integer;
  219.       FMask       : byte;
  220.       FStream     : TStream;
  221.     protected
  222.       procedure ibsReadBuffer;
  223.     public
  224.       constructor Create(aStream : TStream);
  225.       destructor Destroy; override;
  226.  
  227.       function ReadBit : boolean;
  228.       function ReadByte : byte;
  229.   end;
  230.   TOutputBitStream = class
  231.     private
  232.       FAccum      : byte;
  233.       FBuffer     : PAnsiChar;
  234.       FBufPos     : integer;
  235.       FMask       : byte;
  236.       FStream     : TStream;
  237.       FStrmBroken : boolean;
  238.     protected
  239.       procedure obsWriteBuffer;
  240.     public
  241.       constructor Create(aStream : TStream);
  242.       destructor Destroy; override;
  243.  
  244.       procedure WriteBit(aBit : boolean);
  245.       procedure WriteByte(aByte : byte);
  246.   end;
  247. {--------}
  248. constructor TInputBitStream.Create(aStream : TStream);
  249. begin
  250.   inherited Create;
  251.   FStream := aStream;
  252.   GetMem(FBuffer, StreamBufferSize);
  253. end;
  254. {--------}
  255. destructor TInputBitStream.Destroy;
  256. begin
  257.   if (FBuffer <> nil) then begin
  258.     FStream.Seek(-FBufEnd + FBufPos, soFromCurrent);
  259.     FreeMem(FBuffer, StreamBufferSize);
  260.   end;
  261.  
  262.   inherited Destroy;
  263. end;
  264. {--------}
  265. procedure TInputBitStream.ibsReadBuffer;
  266. begin
  267.   FBufEnd := FStream.Read(FBuffer^, StreamBufferSize);
  268.   if (FBufEnd = 0) then
  269.     raise Exception.Create('No more data in input stream');
  270.   FBufPos := 0;
  271. end;
  272. {--------}
  273. function TInputBitStream.ReadBit : boolean;
  274. begin
  275.   {if we have no bits left in the current accumulator, read another
  276.    accumulator byte and reset the mask}
  277.   if (FMask = 0) then begin
  278.     if (FBufPos >= FBufEnd) then
  279.       ibsReadBuffer;
  280.     FAccum := byte(FBuffer[FBufPos]);
  281.     inc(FBufPos);
  282.     FMask := 1;
  283.   end;
  284.   {take the next bit}
  285.   Result := (FAccum and FMask) <> 0;
  286.   FMask := FMask shl 1;          {overflow required on this statement}
  287. end;
  288. {--------}
  289. function TInputBitStream.ReadByte : byte;
  290. var
  291.   Mask   : byte;
  292.   Accum  : byte;
  293.   ByteMask : byte;
  294. begin
  295.   {to speed up this process, we shall take copies of the object's
  296.    fields; at the end we'll copy them back}
  297.   Mask := FMask;
  298.   Accum := FAccum;
  299.   {prepare for the loop(s)}
  300.   ByteMask := 1;
  301.   Result := 0;
  302.   {extract as many bits from the accumulator as we can, refilling as
  303.    necessary}
  304.   while (ByteMask <> 0) do begin
  305.     {if the accumulator is empty, refill it and reset the mask}
  306.     if (Mask = 0) then begin
  307.       if (FBufPos >= FBufEnd) then
  308.         ibsReadBuffer;
  309.       Accum := byte(FBuffer[FBufPos]);
  310.       inc(FBufPos);
  311.       Mask := 1;
  312.     end;
  313.     {get the next bit}
  314.     if ((Accum and Mask) <> 0) then
  315.       Result := Result or ByteMask;
  316.     Mask := Mask shl 1;          {overflow required on this statement}
  317.     ByteMask := ByteMask shl 1;  {overflow required on this statement}
  318.   end;
  319.   {save the new values of the accumulator and the mask}
  320.   FMask := Mask;
  321.   FAccum := Accum;
  322. end;
  323. {--------}
  324. constructor TOutputBitStream.Create(aStream : TStream);
  325. begin
  326.   inherited Create;
  327.   FStream := aStream;
  328.   GetMem(FBuffer, StreamBufferSize);
  329.   FMask := 1; {ready for the first bit to be written}
  330. end;
  331. {--------}
  332. destructor TOutputBitStream.Destroy;
  333. begin
  334.   if (FBuffer <> nil) then begin
  335.     {if Mask is not equal to 1, it means that there are some bits in
  336.      the accumulator that need to be written to the buffer; make sure
  337.      the buffer is written to the underlying stream}
  338.     if not FStrmBroken then begin
  339.       if (FMask <> 1) then begin
  340.         byte(FBuffer[FBufPos]) := FAccum;
  341.         inc(FBufPos);
  342.       end;
  343.       if (FBufPos > 0) then
  344.         obsWriteBuffer;
  345.     end;
  346.     FreeMem(FBuffer, StreamBufferSize);
  347.   end;
  348.   inherited Destroy;
  349. end;
  350. {--------}
  351. procedure TOutputBitStream.obsWriteBuffer;
  352. var
  353.   BytesWrit : longint;
  354. begin
  355.   BytesWrit := FStream.Write(FBuffer^, FBufPos);
  356.   if (BytesWrit <> FBufPos) then begin
  357.     {we had a problem writing the buffer to the stream; raiuse an
  358.      exception to say so, but first make sure so that we don't trigger
  359.      the same exception in the Destroy as well}
  360.     FStrmBroken := true;
  361.     raise Exception.Create('Failed to write buffer to output stream');
  362.   end;
  363.   FBufPos := 0;
  364. end;
  365. {--------}
  366. procedure TOutputBitStream.WriteBit(aBit : boolean);
  367. begin
  368.   {set the next spare bit}
  369.   if aBit then
  370.     FAccum := (FAccum or FMask);
  371.   FMask := FMask shl 1;           {require overflow on this statement}
  372.   {if we have no spare bits left in the current accumulator, write it
  373.    to the buffer, and reset the accumulator and the mask}
  374.   if (FMask = 0) then begin
  375.     byte(FBuffer[FBufPos]) := FAccum;
  376.     inc(FBufPos);
  377.     if (FBufPos >= StreamBufferSize) then
  378.       obsWriteBuffer;
  379.     FAccum := 0;
  380.     FMask := 1;
  381.   end;
  382. end;
  383. {--------}
  384. procedure TOutputBitStream.WriteByte(aByte : byte);
  385. var
  386.   Mask   : byte;
  387.   Accum  : byte;
  388.   ByteMask : byte;
  389. begin
  390.   {to speed up this process, we shall take copies of the object's
  391.    fields; at the end we'll copy them back}
  392.   Mask := FMask;
  393.   Accum := FAccum;
  394.   {prepare for the loop}
  395.   ByteMask := 1;
  396.   {store as many bits to the accumulator as we can, writing it out and
  397.    clearing it as necessary}
  398.   while (ByteMask <> 0) do begin
  399.     {store the next bit}
  400.     if ((aByte and ByteMask) <> 0) then
  401.       Accum := Accum or Mask;
  402.     Mask := Mask shl 1;          {overflow required on this statement}
  403.     ByteMask := ByteMask shl 1;  {overflow required on this statement}
  404.     {if needed, write out the accumulator & reset}
  405.     if (Mask = 0) then begin
  406.       byte(FBuffer[FBufPos]) := Accum;
  407.       inc(FBufPos);
  408.       if (FBufPos >= StreamBufferSize) then
  409.         obsWriteBuffer;
  410.       Accum := 0;
  411.       Mask := 1;
  412.     end;
  413.   end;
  414.   {save the new values of the accumulator and the mask}
  415.   FMask := Mask;
  416.   FAccum := Accum;
  417. end;
  418. {====================================================================}
  419.  
  420.  
  421. {===Exception handling===============================================}
  422. procedure RaiseWriteError;
  423. begin
  424.   raise Exception.Create('Cannot write to Huffman compressed stream');
  425. end;
  426. {--------}
  427. procedure RaiseReadError;
  428. begin
  429.   raise Exception.Create('Expecting more data in Huffman compressed stream, but none left');
  430. end;
  431. {--------}
  432. procedure RaiseReadCorruptError;
  433. begin
  434.   raise Exception.Create('Huffman compressed stream contains corrupted data');
  435. end;
  436. {====================================================================}
  437.  
  438.  
  439. {===Helper routines==================================================}
  440. procedure WriteBits(const aHCode  : THuffmanCode;
  441.                           aStream : TOutputBitStream);
  442. var
  443.   ByteNum : integer;
  444.   BitNum  : integer;
  445.   i       : integer;
  446. begin
  447.   {start off with the correct mask}
  448.   ByteNum := 0;
  449.   BitNum := 7;
  450.   {for all bits...}
  451.   for i := 0 to pred(aHCode.hcBitCount) do begin
  452.     {write the current bit}
  453.     aStream.WriteBit((aHCode.hcCode[ByteNum] and Bit[BitNum]) <> 0);
  454.     {get next bit}
  455.     if (BitNum = 0) then begin
  456.       BitNum := 7;
  457.       inc(ByteNum);
  458.     end
  459.     else
  460.       dec(BitNum);
  461.   end;
  462. end;
  463. {--------}
  464. function ReadChar(aStream : TStream) : char;
  465. {-read a character from the stream}
  466. var
  467.   BytesRead : integer;
  468. begin
  469.   BytesRead := aStream.Read(Result, sizeof(char));
  470.   if (BytesRead <> sizeof(char)) then
  471.     RaiseReadError;
  472. end;
  473. {--------}
  474. function ReadValue(aStream : TStream) : longint;
  475. {-read an integer value from the stream}
  476. var
  477.   BytesRead : integer;
  478.   ValueType : byte;
  479. begin
  480.   Result := 0;
  481.   BytesRead := aStream.Read(ValueType, sizeof(ValueType));
  482.   if (BytesRead <> sizeof(ValueType)) then
  483.     RaiseReadError;
  484.   case ValueType of
  485.     vaByte :
  486.       begin
  487.         BytesRead := aStream.Read(Result, sizeof(byte));
  488.         if (BytesRead <> sizeof(byte)) then
  489.           RaiseReadError;
  490.       end;
  491.     vaWord :
  492.       begin
  493.         BytesRead := aStream.Read(Result, sizeof(word));
  494.         if (BytesRead <> sizeof(word)) then
  495.           RaiseReadError;
  496.       end;
  497.     vaLongint :
  498.       begin
  499.         BytesRead := aStream.Read(Result, sizeof(longint));
  500.         if (BytesRead <> sizeof(longint)) then
  501.           RaiseReadError;
  502.       end;
  503.   else {it's an unknown value type}
  504.     RaiseReadCorruptError;
  505.   end;{case}
  506. end;
  507. {--------}
  508. procedure WriteChar(aStream : TStream; aChar : char);
  509. {-write a character to the stream}
  510. var
  511.   BytesWrit : integer;
  512. begin
  513.   BytesWrit := aStream.Write(aChar, sizeof(char));
  514.   if (BytesWrit <> sizeof(char)) then
  515.     RaiseWriteError;
  516. end;
  517. {--------}
  518. procedure WriteValue(aStream : TStream; aValue : longint);
  519. {-write an integer value to the stream}
  520. var
  521.   BytesWrit : integer;
  522.   ValueType : byte;
  523. begin
  524.   {if the value is between 0 and 255 write a byte to the stream}
  525.   if (0 <= aValue) and (aValue < 256) then begin
  526.     ValueType := vaByte;
  527.     BytesWrit := aStream.Write(ValueType, sizeof(ValueType));
  528.     if (BytesWrit <> sizeof(ValueType)) then
  529.       RaiseWriteError;
  530.     BytesWrit := aStream.Write(aValue, sizeof(byte));
  531.     if (BytesWrit <> sizeof(byte)) then
  532.       RaiseWriteError;
  533.   end
  534.   {if the value is between 256 and 65535 write a word to the stream}
  535.   else if (256 <= aValue) and (aValue < 64*1024) then begin
  536.     ValueType := vaWord;
  537.     BytesWrit := aStream.Write(ValueType, sizeof(ValueType));
  538.     if (BytesWrit <> sizeof(ValueType)) then
  539.       RaiseWriteError;
  540.     BytesWrit := aStream.Write(aValue, sizeof(word));
  541.     if (BytesWrit <> sizeof(word)) then
  542.       RaiseWriteError;
  543.   end
  544.   {otherwise write a longint to the stream}
  545.   else begin
  546.     ValueType := vaLongint;
  547.     BytesWrit := aStream.Write(ValueType, sizeof(ValueType));
  548.     if (BytesWrit <> sizeof(ValueType)) then
  549.       RaiseWriteError;
  550.     BytesWrit := aStream.Write(aValue, sizeof(longint));
  551.     if (BytesWrit <> sizeof(longint)) then
  552.       RaiseWriteError;
  553.   end;
  554. end;
  555. {--------}
  556. procedure CalcCharDistribution(aStream : TStream;
  557.                                aHTree  : PHuffmanTree);
  558. {-calculate the character distribution from the data in the stream;
  559.   fill the first 256 entries in the Huffman tree with the information}
  560. var
  561.   i         : integer;
  562.   Buffer    : PByteArray;
  563.   BytesRead : integer;
  564. begin
  565.   aStream.Position := 0;
  566.   GetMem(Buffer, 1024);
  567.   try
  568.     BytesRead := aStream.Read(Buffer^, 1024);
  569.     while (BytesRead <> 0) do begin
  570.       for i := pred(BytesRead) downto 0 do
  571.         inc(aHTree^[Buffer^[i]].hnCount);
  572.       BytesRead := aStream.Read(Buffer^, 1024);
  573.     end;
  574.   finally
  575.     FreeMem(Buffer, 1024);
  576.   end;
  577. end;
  578. {--------}
  579. procedure ConvertCodeStr(const aHCode  : THuffmanCodeStr;
  580.                                aHCodes : PHuffmanCodes;
  581.                                aNodeInx: integer);
  582. {-convert a code string into binary; store in codes array}
  583. var
  584.   TempCode : THuffmanCode;
  585.   ByteNum  : integer;
  586.   BitNum   : byte;
  587.   i        : integer;
  588. begin
  589.   {set the binary code to zeros, so we only have to record '1' bits}
  590.   FillChar(TempCode, sizeof(TempCode), 0);
  591.   {store the code length}
  592.   TempCode.hcBitCount := length(aHCode);
  593.   {fill the bits from the left in the binary code}
  594.   ByteNum := 0;
  595.   BitNum := 7;
  596.   for i := 1 to length(aHCode) do begin
  597.     if (aHCode[i] = '1') then
  598.       TempCode.hcCode[ByteNum] :=
  599.          TempCode.hcCode[ByteNum] or Bit[BitNum];
  600.     if (BitNum = 0) then begin
  601.       BitNum := 7;
  602.       inc(ByteNum);
  603.     end
  604.     else
  605.       dec(BitNum);
  606.   end;
  607.   {store binary code in the codes array}
  608.   aHCodes^[aNodeInx] := TempCode;
  609. end;
  610. {--------}
  611. procedure CalcHuffmanCodePrim(aNodeInx : integer;
  612.                           var aHCode   : THuffmanCodeStr;
  613.                               aHTree   : PHuffmanTree;
  614.                               aHCodes  : PHuffmanCodes);
  615. {-recursive routine to calculate all the Huffman codes for a given
  616.   Huffman tree}
  617. begin
  618.   {if the current node is not a leaf, then visit the left subtree
  619.    followed by the right subtree}
  620.   if (aNodeInx >= 256) then begin
  621.     {add a 0 bit on the end of the code string}
  622.     inc(aHCode[0]);
  623.     aHCode[length(aHCode)] := '0';
  624.     {visit the left subtree}
  625.     CalcHuffmanCodePrim(aHTree^[aNodeInx].hnLeftInx, aHCode, aHTree, aHCodes);
  626.     {add a 1 bit on the end of the code string}
  627.     aHCode[length(aHCode)] := '1';
  628.     {visit the right subtree}
  629.     CalcHuffmanCodePrim(aHTree^[aNodeInx].hnRightInx, aHCode, aHTree, aHCodes);
  630.     dec(aHCode[0]);
  631.   end
  632.   {if the current node is a leaf, record the current code in the codes
  633.    array}
  634.   else begin
  635.     ConvertCodeStr(aHCode, aHCodes, aNodeInx);
  636.   end;
  637. end;
  638. {--------}
  639. procedure CalcHuffmanCodes(aHTree  : PHuffmanTree;
  640.                            aRoot   : integer;
  641.                            aHCodes : PHuffmanCodes);
  642. {-calculate the Huffman codes for a Huffman tree}
  643. var
  644.   HCode : THuffmanCodeStr;
  645. begin
  646.   {clear the codes array}
  647.   FillChar(aHCodes^, sizeof(aHCodes^), 0);
  648.   {to calculate the codes we have to visit every leaf and for each
  649.    leaf we'll have accumulated a series of bits (going left from a
  650.    parent node to a child node is a 0 bit, going right is a 1 bit);
  651.    for the walk through the tree we'll use a modified inorder
  652.    traversal (ie, visit the left subtree, there's no need to visit the
  653.    node itself, visit the right subtree); because we know the tree has
  654.    a maximum depth of 255, we'll use recursion without getting too
  655.    worried about blowing the stack}
  656.   HCode := '';
  657.   CalcHuffmanCodePrim(aRoot, HCode, aHTree, aHCodes);
  658. end;
  659. {--------}
  660. function ReadNode(aStream : TInputBitStream;
  661.                   aHTree  : PHuffmanTree;
  662.               var aMaxInx : integer) : integer;
  663. var
  664.   IsLeaf  : boolean;
  665. begin
  666.   {read the next bit to determine which node we have to create}
  667.   IsLeaf := aStream.ReadBit;
  668.   {if it's a leaf then return its node index (ie, the character)}
  669.   if IsLeaf then
  670.     Result := aStream.ReadByte
  671.   {if it's an internal node, get the left and right subtrees}
  672.   else begin
  673.     inc(aMaxInx);
  674.     Result := aMaxInx;
  675.     aHTree^[Result].hnLeftInx := ReadNode(aStream, aHTree, aMaxInx);
  676.     aHTree^[Result].hnRightInx := ReadNode(aStream, aHTree, aMaxInx);
  677.   end;
  678. end;
  679. {--------}
  680. function ReadCharDistribution(aStream : TInputBitStream;
  681.                               aHTree  : PHuffmanTree) : integer;
  682. {-read a character distribution from a stream}
  683. var
  684.   MaxInx : integer;
  685. begin
  686.   MaxInx := 255;
  687.   Result := ReadNode(aStream, aHTree, MaxInx);
  688. end;
  689. {--------}
  690. procedure WriteNode(aStream  : TOutputBitStream;
  691.                     aHTree   : PHuffmanTree;
  692.                     aNodeInx : integer);
  693. begin
  694.   {for a leaf, write a 1 bit, followed by the character}
  695.   if (aNodeInx < 256) then begin
  696.     aStream.WriteBit(true);
  697.     aStream.WriteByte(aNodeInx);
  698.   end
  699.   {for an internal node, write a 0 bit, then the left subtree, then
  700.    the right subtree}
  701.   else begin
  702.     aStream.WriteBit(false);
  703.     WriteNode(aStream, aHTree, aHTree^[aNodeInx].hnLeftInx);
  704.     WriteNode(aStream, aHTree, aHTree^[aNodeInx].hnRightInx);
  705.   end;
  706. end;
  707. {--------}
  708. procedure WriteCharDistribution(aStream : TOutputBitStream;
  709.                                 aHTree  : PHuffmanTree;
  710.                                 aRootInx: integer);
  711. {-write a character distribution to a stream}
  712. begin
  713.   WriteNode(aStream, aHTree, aRootInx);
  714. end;
  715. {--------}
  716. procedure BuildHuffmanTree(aHTree         : PHuffmanTree;
  717.                        var aLastParentInx : integer);
  718. {-given a Huffman tree just containing the character distributions,
  719.   build the entire tree; return the index of the root}
  720. var
  721.   i  : integer;
  722.   PQ : THuffmanPriorityQueue;
  723.   Node1Inx  : longint;
  724.   Node2Inx  : longint;
  725.   ParentInx : integer;
  726. begin
  727.   ParentInx := aLastParentInx;
  728.   {create a priority queue}
  729.   PQ := THuffmanPriorityQueue.Create(aHTree);
  730.   try
  731.     {add all the non-zero nodes to the queue}
  732.     for i := 0 to 255 do
  733.       if (aHTree^[i].hnCount <> 0) then
  734.         PQ.Add(i);
  735.     {SPECIAL CASE: there is only one non-zero node, ie the input
  736.      stream consisted of just one character, repeated one or more
  737.      times; set the parent index to the single character}
  738.     if (PQ.Count = 1) then
  739.       ParentInx := PQ.Remove
  740.     {otherwise we have the normal, many different chars, case}
  741.     else
  742.       {while there is more than one item in the queue, remove the two
  743.        smallest, join them to a new parent, and add the parent to the
  744.        queue}
  745.       while (PQ.Count > 1) do begin
  746.         Node1Inx := PQ.Remove;
  747.         Node2Inx := PQ.Remove;
  748.         inc(ParentInx);
  749.         with aHTree^[ParentInx] do begin
  750.           hnLeftInx := Node1Inx;
  751.           hnRightInx := Node2Inx;
  752.           hnCount := aHTree^[Node1Inx].hnCount +
  753.                      aHTree^[Node2Inx].hnCount;
  754.         end;
  755.         PQ.Add(ParentInx);
  756.       end;
  757.   finally
  758.     PQ.Free;
  759.   end;
  760.   aLastParentInx := ParentInx;
  761. end;
  762. {--------}
  763. procedure DoHuffmanCompression(aInStream  : TStream;
  764.                                aOutStream : TOutputBitStream;
  765.                                aHCodes    : PHuffmanCodes);
  766. {-given an array of Huffman codes, compress the input stream to the
  767.   output stream}
  768. var
  769.   B : byte;
  770.   i : integer;
  771. begin
  772.   {reset the input stream to the start}
  773.   aInStream.Position := 0;
  774.   {for each character in the input stream, write its Huffman code to
  775.    the output stream}
  776.   for i := 0 to pred(aInStream.Size) do begin
  777.     aInStream.Read(B, sizeof(B));
  778.     WriteBits(aHCodes^[B], aOutStream);
  779.   end;
  780. end;
  781. {--------}
  782. procedure DoHuffmanDecompression(aInStream  : TInputBitStream;
  783.                                  aOutStream : TStream;
  784.                                  aHTree     : PHuffmanTree;
  785.                                  aRoot      : integer);
  786. {-given a Huffman tree, decompress the input stream to the output
  787.   stream}
  788. var
  789.   CharCount      : longint;
  790.   TotalCharCount : longint;
  791.   CurrNode       : integer;
  792.   GoLeft         : boolean;
  793.   Ch             : char;
  794. begin
  795.   {calculate the total number of characters to decompress; preset the
  796.    loop variables}
  797.   TotalCharCount := aHTree^[aRoot].hnCount;
  798.   CharCount := 0;
  799.   CurrNode := aRoot;
  800.   {repeat until all the characters have been decompressed}
  801.   while CharCount < TotalCharCount do begin
  802.     {read the next bit}
  803.     GoLeft := not aInStream.ReadBit;
  804.     {walk down the Huffman tree}
  805.     if GoLeft then
  806.       CurrNode := aHTree^[CurrNode].hnLeftInx
  807.     else
  808.       CurrNode := aHTree^[CurrNode].hnRightInx;
  809.     {if we have reached a leaf, output the character concerned, and
  810.      reset the current node to the root}
  811.     if (CurrNode < 256) then begin
  812.       Ch := char(CurrNode);
  813.       aOutStream.Write(Ch, sizeof(byte));
  814.       CurrNode := aRoot;
  815.       inc(CharCount);
  816.     end;
  817.   end;
  818. end;
  819. {--------}
  820. procedure WriteMultipleChars(aStream : TStream;
  821.                              aCh     : char;
  822.                              aCount  : longint);
  823. {-write several copies of a character to a stream}
  824. const
  825.   BufferSize = 1024;
  826. var
  827.   Buffer       : PByteArray;
  828.   BytesToWrite : integer;
  829.   BytesWrit    : integer;
  830. begin
  831.   GetMem(Buffer, BufferSize);
  832.   try
  833.     FillChar(Buffer^, BufferSize, aCh);
  834.     while (aCount > 0) do begin
  835.       if (aCount < BufferSize) then
  836.         BytesToWrite := aCount
  837.       else
  838.         BytesToWrite := BufferSize;
  839.       BytesWrit := aStream.Write(Buffer^, BytesToWrite);
  840.       dec(aCount, BytesWrit);
  841.     end;
  842.   finally
  843.     FreeMem(Buffer, BufferSize);
  844.   end;
  845. end;
  846. {====================================================================}
  847.  
  848.  
  849. {===Interfaced routines==============================================}
  850. procedure HuffmanCompress(aInStream, aOutStream : TStream);
  851. var
  852.   HTree  : PHuffmanTree;
  853.   Root   : integer;
  854.   HCodes : PHuffmanCodes;
  855.   Size   : longint;
  856.   OutputBitStream : TOutputBitStream;
  857. begin
  858.   {write the number of characters in the input stream to the output
  859.    stream; this aids in decompression--we know when to stop}
  860.   Size := aInStream.Size;
  861.   aOutStream.Write(Size, sizeof(Size));
  862.   {if there's nothing to compress, exit now}
  863.   if (Size = 0) then
  864.     Exit;
  865.   {prepare}
  866.   HTree := nil;
  867.   OutputBitStream := nil;
  868.   try
  869.     {allocate the Huffman tree}
  870.     New(HTree);
  871.     {initialise the tree}
  872.     FillChar(HTree^, sizeof(HTree^), 0);
  873.     {get the distribution of characters in the input stream, place in
  874.      the first 256 elements of the Huffman tree}
  875.     CalcCharDistribution(aInStream, HTree);
  876.     {build the Huffman tree}
  877.     Root := 255;
  878.     BuildHuffmanTree(HTree, Root);
  879.     {create the output bit stream}
  880.     OutputBitStream := TOutputBitStream.Create(aOutStream);
  881.     {when this point is reached we know the Huffman tree is rooted at
  882.      Root; if Root is a leaf, then the input stream just consisted of
  883.      repetitions of one character, so output the minimal compressed
  884.      data, essentially RLE compression}
  885.     if (Root < 256) then
  886.       WriteCharDistribution(OutputBitStream, HTree, Root)
  887.     else {Root is not a leaf} begin
  888.       {allocate the codes array}
  889.       New(HCodes);
  890.       try
  891.         {calculate all the codes}
  892.         CalcHuffmanCodes(HTree, Root, HCodes);
  893.         {we are now ready to compress the input stream, however we
  894.          must first output the tree to the output stream to aid the
  895.          decompressor}
  896.         WriteCharDistribution(OutputBitStream, HTree, Root);
  897.         {compress the characters in the input stream}
  898.         DoHuffmanCompression(aInStream, OutputBitStream, HCodes);
  899.       finally
  900.         Dispose(HCodes);
  901.       end;
  902.     end;
  903.   finally
  904.     if (HTree <> nil) then
  905.       Dispose(HTree);
  906.     OutputBitStream.Free;
  907.   end;
  908. end;
  909. {--------}
  910. procedure HuffmanDecompress(aInStream, aOutStream : TStream);
  911. var
  912.   HTree : PHuffmanTree;
  913.   Root  : integer;
  914.   Size  : longint;
  915.   InputBitStream : TInputBitStream;
  916. begin
  917.   {if there's nothing to decompress, exit now}
  918.   if (aInStream.Size = 0) then
  919.     Exit;
  920.   aInStream.ReadBuffer(Size, sizeof(Size));
  921.   if (Size = 0) then
  922.     Exit;
  923.   {prepare}
  924.   HTree := nil;
  925.   InputBitStream := nil;
  926.   try
  927.     {allocate the Huffman tree}
  928.     New(HTree);
  929.     {initialise the tree}
  930.     FillChar(HTree^, sizeof(HTree^), 0);
  931.     {create the input bit stream}
  932.     InputBitStream := TInputBitStream.Create(aInStream);
  933.     {read the Huffman tree from the input stream}
  934.     Root := ReadCharDistribution(InputBitStream, HTree);
  935.     {when this point is reached we know the Huffman tree is rooted at
  936.      Root; if Root is a leaf, then the original stream just consisted
  937.      of repetitions of one character}
  938.     if (Root < 256) then
  939.       WriteMultipleChars(aOutStream, char(Root), HTree^[Root].hnCount)
  940.     {otherwise, using the Huffman tree, decompress the characters in
  941.      the input stream; note that the number of chars to decompress
  942.      is the count at the root of the Huffman tree}
  943.     else begin
  944.       HTree^[Root].hnCount := Size;
  945.       DoHuffmanDecompression(InputBitStream, aOutStream, HTree, Root);
  946.     end;
  947.   finally
  948.     if (HTree <> nil) then
  949.       Dispose(HTree);
  950.     InputBitStream.Free;
  951.   end;
  952. end;
  953. {====================================================================}
  954.  
  955.  
  956. {====================================================================}
  957. type
  958.   TBlockStream = class(TCustomMemoryStream)
  959.     private
  960.       FPosition : integer;
  961.     public
  962.       constructor Create(var aBuffer; aSize : integer);
  963.       function Write(const aBuffer; aCount: longint) : longint; override;
  964.   end;
  965. {--------}
  966. constructor TBlockStream.Create(var aBuffer; aSize : integer);
  967. begin
  968.   inherited Create;
  969.   SetPointer(@aBuffer, aSize);
  970. end;
  971. {--------}
  972. function TBlockStream.Write(const aBuffer; aCount: longint) : longint;
  973. begin
  974.   Move(aBuffer, (PChar(Memory) + FPosition)^, aCount);
  975.   inc(FPosition, aCount);
  976.   Result := aCount;
  977. end;
  978. {====================================================================}
  979. procedure HuffmanCompressBlock(var aBuffer;
  980.                                    aSize      : integer;
  981.                                    aOutStream : TStream);
  982. var
  983.   MemStrm : TBlockStream;
  984. begin
  985.   MemStrm := TBlockStream.Create(aBuffer, aSize);
  986.   try
  987.     HuffmanCompress(MemStrm, aOutStream);
  988.   finally
  989.     MemStrm.Free;
  990.   end;
  991. end;
  992. {--------}
  993. procedure HuffmanDecompressBlock(aInStream : TStream;
  994.                              var aBuffer;
  995.                                  aSize     : integer);
  996. var
  997.   MemStrm : TBlockStream;
  998. begin
  999.   MemStrm := TBlockStream.Create(aBuffer, aSize);
  1000.   try
  1001.     HuffmanDecompress(aInStream, MemStrm);
  1002.   finally
  1003.     MemStrm.Free;
  1004.   end;
  1005. end;
  1006. {====================================================================}
  1007.  
  1008.  
  1009. end.
  1010.